// This module is used to generate signal - any_dst_data_valid
// Avoid timing faild of operation - |front_dst_data_valid

`timescale 1ns / 1ps

`include "data_width.vh"

module get_edge_info_pre_0 #(parameter
    DST_ID_DWIDTH       = `DST_ID_DWIDTH,
    VERTEX_MASK_WIDTH   = `VERTEX_MASK_WIDTH,
    VERTEX_PIPE_NUM     = `VERTEX_PIPE_NUM
    ) (
        input                                                   clk,
        input                                                   front_rst,
        input                                                   front_finish_read,
        input [DST_ID_DWIDTH * VERTEX_PIPE_NUM - 1 : 0]         front_dst_id,
        input [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0]     front_edge_info_mask_l,
        input [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0]     front_edge_info_mask_r,
        input [VERTEX_PIPE_NUM - 1 : 0]                         front_dst_data_valid,
        input                                                   back_stage_vertex_full,

        output                                                  rst,
        output                                                  buffer_full_vertex,
        output                                                  any_dst_data_valid,
        output                                                  finish_read,
        output [DST_ID_DWIDTH * VERTEX_PIPE_NUM - 1 : 0]        dst_id,
        output [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0]    edge_info_mask_l,
        output [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0]    edge_info_mask_r,
        output [VERTEX_PIPE_NUM - 1 : 0]                        dst_data_valid);

    get_edge_info_pre_0_para_tran P (
        .clk        (clk),
        .front_rst  (front_rst),

        .rst        (rst));
    
    get_edge_info_pre_0_vertex_tran V (
        .clk                (clk),
        .rst                (front_rst),
        .front_finish_read  (front_finish_read),
        .front_dst_id           (front_dst_id),
        .front_edge_info_mask_l (front_edge_info_mask_l),
        .front_edge_info_mask_r (front_edge_info_mask_r),
        .front_dst_data_valid   (front_dst_data_valid),
        .back_stage_vertex_full (back_stage_vertex_full),

        .buffer_full_vertex     (buffer_full_vertex),
        .any_dst_data_valid     (any_dst_data_valid),
        .finish_read            (finish_read),
        .dst_id                 (dst_id),
        .edge_info_mask_l       (edge_info_mask_l),
        .edge_info_mask_r       (edge_info_mask_r),
        .dst_data_valid         (dst_data_valid));

endmodule

module get_edge_info_pre_0_para_tran (
    input       clk,
    input       front_rst,

    output reg  rst);

    always @ (posedge clk) begin
        rst <= front_rst;
    end

endmodule

module get_edge_info_pre_0_vertex_tran #(parameter
    DST_ID_DWIDTH       = `DST_ID_DWIDTH,
    VERTEX_MASK_WIDTH   = `VERTEX_MASK_WIDTH,
    VERTEX_PIPE_NUM     = `VERTEX_PIPE_NUM
    ) (
        input                                                       clk,
        input                                                       rst,
        input                                                       front_finish_read,
        input [DST_ID_DWIDTH * VERTEX_PIPE_NUM - 1 : 0]             front_dst_id,
        input [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0]         front_edge_info_mask_l,
        input [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0]         front_edge_info_mask_r,
        input [VERTEX_PIPE_NUM - 1 : 0]                             front_dst_data_valid,
        input                                                       back_stage_vertex_full,

        output reg                                                  buffer_full_vertex,
        output reg                                                  any_dst_data_valid,
        output reg                                                  finish_read,
        output reg [DST_ID_DWIDTH * VERTEX_PIPE_NUM - 1 : 0]        dst_id,
        output reg [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0]    edge_info_mask_l,
        output reg [VERTEX_MASK_WIDTH * VERTEX_PIPE_NUM - 1 : 0]    edge_info_mask_r,
        output reg [VERTEX_PIPE_NUM - 1 : 0]                        dst_data_valid);
    
    wire            front_any_dst_data_valid;
    wire [7 : 0]    front_any_dst_data_valid_p_1;
    wire [3 : 0]    front_any_dst_data_valid_p_2;
    wire [1 : 0]    front_any_dst_data_valid_p_3;

    assign front_any_dst_data_valid = front_any_dst_data_valid_p_3[0] || front_any_dst_data_valid_p_3[1];

    generate
        genvar i;
        for (i = 0; i < 8; i = i + 1) begin
            assign front_any_dst_data_valid_p_1[i] = front_dst_data_valid[i] || front_dst_data_valid[i + 8];
        end
        for (i = 0; i < 4; i = i + 1) begin
            assign front_any_dst_data_valid_p_2[i] = front_any_dst_data_valid_p_1[i] || front_any_dst_data_valid_p_1[i + 4];
        end
        for (i = 0; i < 2; i = i + 1) begin
            assign front_any_dst_data_valid_p_3[i] = front_any_dst_data_valid_p_2[i] || front_any_dst_data_valid_p_2[i + 2];
        end
    endgenerate
    
    always @ (posedge clk) begin
        if (rst) begin
            buffer_full_vertex  <= 1'b1;
            any_dst_data_valid  <= 1'b0;
            finish_read         <= 1'b0;
            dst_id              <= 0;
            edge_info_mask_l    <= 0;
            edge_info_mask_r    <= {VERTEX_MASK_WIDTH{1'b1}};
            dst_data_valid      <= {VERTEX_PIPE_NUM{1'b0}};
        end
        else begin
            buffer_full_vertex  <= back_stage_vertex_full;
            finish_read         <= front_finish_read;
            dst_id              <= front_dst_id;
            edge_info_mask_l    <= front_edge_info_mask_l;
            edge_info_mask_r    <= front_edge_info_mask_r;
            dst_data_valid      <= front_dst_data_valid;
            any_dst_data_valid  <= front_any_dst_data_valid;
        end
    end

endmodule